[JOI2019]三级跳

2019-11-15
JOI

题意

给出${w_i}$,多次询问给出l,r,求满足$l\leq a<b<c\leq r$,$b-a\leq c-b$的$w_a+w_b+w_c$的最大值

$n,q\leq 5\cdot 10^5$

题解

如果一组ab可能合法,当且仅当ab中间不存在权值比$w_a$或者$w_b​$大的

可以用单调栈求出这些数对,对数是$O(n)$的

然后扫描线+线段树维护区间w+Max的最大值即可

调试记录

注意扫描线要从后往前扫,因为从前往后的话最大值可能是从l前面跳过来的

从后往前扫容易控制边界

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include <cstdio>
#include <vector>
const int maxn = 5e5 + 5;
using namespace std;
int w[maxn], n, Q;
int s[maxn], top = 0;
vector <int> p[maxn];
vector <pair<int, int> > q[maxn];
struct T{
struct A{
int l, r, Max, v, lazy;
}a[maxn << 2];
void build(int cur, int l, int r){
a[cur].l = l, a[cur].r = r;
if (l == r){a[cur].v = w[l]; return;}
int mid = l + r >> 1;
build(cur << 1, l, mid);
build(cur << 1 | 1, mid + 1, r);
a[cur].v = max(a[cur << 1].v, a[cur << 1 | 1].v);
}
void pushdown(int cur){
if (!a[cur].lazy) return;
a[cur << 1].lazy = max(a[cur << 1].lazy, a[cur].lazy);
a[cur << 1].Max = max(a[cur << 1].Max, a[cur].lazy + a[cur << 1].v);
a[cur << 1 | 1].lazy = max(a[cur << 1 | 1].lazy, a[cur].lazy);
a[cur << 1 | 1].Max = max(a[cur << 1 | 1].Max, a[cur].lazy + a[cur << 1 | 1].v);
a[cur].lazy = 0;
}
void upd(int cur, int l, int r, int k){
if (a[cur].l > r || a[cur].r < l) return;
if (a[cur].l >= l && a[cur].r <= r){
a[cur].Max = max(a[cur].Max, a[cur].v + k);
a[cur].lazy = max(a[cur].lazy, k);
return;
}
pushdown(cur);
upd(cur << 1, l, r, k);
upd(cur << 1 | 1, l, r, k);
a[cur].Max = max(a[cur << 1].Max, a[cur << 1 | 1].Max);
}
int Query(int cur, int l, int r){
if (a[cur].l > r || a[cur].r < l) return 0;
if (a[cur].l >= l && a[cur].r <= r) return a[cur].Max;
pushdown(cur); return max(Query(cur << 1, l, r), Query(cur << 1 | 1, l, r));
}
}t; int ans[maxn];
int main(){
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%d", w + i);
for (int i = 1; i <= n; i++){
while (top && w[s[top]] < w[i]) p[s[top--]].push_back(i);
p[s[top]].push_back(i); s[++top] = i;
} scanf("%d", &Q);
for (int l, r, i = 1; i <= Q; i++){
scanf("%d%d", &l, &r); q[l].push_back(make_pair(r, i));
} t.build(1, 1, n);
for (int i = n; i >= 1; i--){
for (int j = 0; j < p[i].size(); j++){
// printf("%d: %d\n", i, p[i][j]);
if (2 * p[i][j] - i <= n) t.upd(1, 2 * p[i][j] - i, n, w[i] + w[p[i][j]]);
}
for (int j = 0; j < q[i].size(); j++)
ans[q[i][j].second] = t.Query(1, i, q[i][j].first);
}
for (int i = 1; i <= Q; i++) printf("%d\n", ans[i]);
return 0;
}